package com.fastplatform.service;

import cn.dev33.satoken.stp.StpUtil;
import com.fastplatform.entity.Menu;
import com.fastplatform.entity.User;
import com.fastplatform.repository.MenuRepository;
import com.fastplatform.repository.RoleMenuRepository;
import com.fastplatform.repository.UserRepository;
import com.fastplatform.specification.MenuSpecification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import jakarta.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class MenuService {

    @Autowired
    private MenuRepository menuRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleMenuRepository roleMenuRepository;

    /**
     * 获取当前用户的菜单树
     */
    @Cacheable(value = "userMenus", key = "#root.methodName + '_' + T(cn.dev33.satoken.stp.StpUtil).getLoginIdAsLong()")
    public List<Menu> getCurrentUserMenus() {
        Long userId = StpUtil.getLoginIdAsLong();
        User user = userRepository.findById(userId).orElse(null);
        if (user == null) {
            return new ArrayList<>();
        }

        // 管理员获取所有菜单
        if (user.getUserType() != null && user.getUserType() == 1) {
            return buildMenuTree(menuRepository.findByDeletedFalseAndStatusOrderBySort(1));
        }

        // 普通用户根据角色获取菜单
        List<Menu> menus = menuRepository.findAll(MenuSpecification.findMenusByUserId(userId));
        return buildMenuTree(menus);
    }

    /**
     * 获取所有菜单（用于菜单管理）
     */
    @Cacheable(value = "allMenus", key = "#root.methodName")
    public List<Menu> getAllMenus() {
        List<Menu> menus = menuRepository.findAll();
        return buildMenuTree(menus);
    }

    /**
     * 根据条件获取菜单列表（使用JPA Criteria Queries）
     */
    public List<Menu> getMenuList(String menuName, Integer menuType, Integer status) {
        // 如果有搜索条件，需要构建包含匹配节点及其完整路径的树形结构
        if (menuName != null || menuType != null || status != null) {
            List<Menu> matchedMenus = menuRepository.findAll(MenuSpecification.findMenusByConditions(menuName, menuType, status));
            if (matchedMenus.isEmpty()) {
                return new ArrayList<>();
            }
            
            // 获取所有菜单用于构建完整树形结构
            List<Menu> allMenus = menuRepository.findAll(MenuSpecification.findMenusByConditions(null, null, null));
            
            // 找到匹配菜单的所有相关节点（父节点和子节点）
            List<Menu> relatedMenus = findRelatedMenus(matchedMenus, allMenus);
            
            return buildMenuTree(relatedMenus);
        }
        
        // 没有搜索条件时，获取所有菜单并构建树形结构
        List<Menu> allMenus = menuRepository.findAll(MenuSpecification.findMenusByConditions(null, null, null));
        return buildMenuTree(allMenus);
    }

    /**
     * 保存菜单
     */
    @Transactional
    @CacheEvict(value = {"userMenus", "allMenus"}, allEntries = true)
    public Menu saveMenu(Menu menu) {
        if (menu.getId() == null) {
            // 新增
            menu.setCreateTime(LocalDateTime.now());
        }
        menu.setUpdateTime(LocalDateTime.now());
        return menuRepository.save(menu);
    }

    /**
     * 删除菜单
     */
    @Transactional
    @CacheEvict(value = {"userMenus", "allMenus"}, allEntries = true)
    public void deleteMenu(Long id) {
        Menu menu = menuRepository.findById(id).orElse(null);
        if (menu != null) {
            menu.setDeleted(true);
            menu.setUpdateTime(LocalDateTime.now());
            menuRepository.save(menu);

            // 删除角色菜单关联
            roleMenuRepository.deleteByMenuId(id);
        }
    }

    /**
     * 根据ID获取菜单
     */
    public Menu getMenuById(Long id) {
        return menuRepository.findById(id).orElse(null);
    }

    /**
     * 构建菜单树
     */
    private List<Menu> buildMenuTree(List<Menu> menus) {
        // 获取所有顶级菜单（parentId为null或0的菜单）
        List<Menu> rootMenus = menus.stream()
                .filter(menu -> menu.getParentId() == null || menu.getParentId().equals(0L))
                .sorted((m1, m2) -> {
                    int sort1 = m1.getSort() != null ? m1.getSort() : 0;
                    int sort2 = m2.getSort() != null ? m2.getSort() : 0;
                    return sort1 - sort2;
                })
                .collect(Collectors.toList());

        // 递归设置子菜单
        for (Menu menu : rootMenus) {
            menu.setChildren(getChildren(menu.getId(), menus));
        }

        return rootMenus;
    }

    /**
     * 获取子菜单
     */
    private List<Menu> getChildren(Long parentId, List<Menu> menus) {
        List<Menu> children = menus.stream()
                .filter(menu -> parentId.equals(menu.getParentId()))
                .sorted((m1, m2) -> {
                    int sort1 = m1.getSort() != null ? m1.getSort() : 0;
                    int sort2 = m2.getSort() != null ? m2.getSort() : 0;
                    return sort1 - sort2;
                })
                .collect(Collectors.toList());

        for (Menu menu : children) {
            menu.setChildren(getChildren(menu.getId(), menus));
        }

        return children;
    }

    /**
     * 找到匹配菜单的所有相关节点（只包含父节点，不包含子节点）
     */
    private List<Menu> findRelatedMenus(List<Menu> matchedMenus, List<Menu> allMenus) {
        Set<Long> relatedMenuIds = new HashSet<>();
        
        // 添加匹配的菜单ID
        for (Menu menu : matchedMenus) {
            relatedMenuIds.add(menu.getId());
        }
        
        // 找到所有父节点
        for (Menu matchedMenu : matchedMenus) {
            findAllParents(matchedMenu.getParentId(), allMenus, relatedMenuIds);
        }
        
        // 返回所有相关菜单
        return allMenus.stream()
                .filter(menu -> relatedMenuIds.contains(menu.getId()))
                .collect(Collectors.toList());
    }
    
    /**
     * 递归查找所有父节点
     */
    private void findAllParents(Long parentId, List<Menu> allMenus, Set<Long> relatedMenuIds) {
        if (parentId == null || parentId == 0) {
            return;
        }
        
        for (Menu menu : allMenus) {
            if (menu.getId().equals(parentId)) {
                relatedMenuIds.add(menu.getId());
                findAllParents(menu.getParentId(), allMenus, relatedMenuIds);
                break;
            }
        }
    }
    

}